package xyz.scootaloo.kami.server.service

import io.vertx.core.Future
import xyz.scootaloo.kami.server.standard.CacheInvalidException
import xyz.scootaloo.kami.server.service.impl.InternalTokenServiceImpl

/**
 * @author flutterdash@qq.com
 * @since 2022/2/4 16:11
 */
interface TokenService {

    /**
     * 此方法会生成一对公钥和私钥, 生成成功后, 私钥会保存在缓存中, 私钥有效期默认5秒;
     * 然后公钥返回给客户端, 用于客户端对数据加密处理; 私钥用于服务端对客户端的发送的数据进行解密;
     *
     * 为了节省内存占用, 公钥和私钥都进行了压缩处理, encodeKey = base64(key)
     *
     * @param clientId 使用一个字符串来标记生成这个公私钥的用户的身份;
     *                 当多个用户同时访问此功能时, 需要对用户进行更细致的区分, 防止多个用户共用了同一个私钥
     * @param expiryTime 失效时间(单位毫秒), 当用户提交需要解密的数据超过这个时间则无法解密
     *
     * @return [EncodeToken]
     */
    fun generateToken(clientId: String, expiryTime: Long = 5000): EncodeToken

    /**
     * 解密操作
     *
     * 按照[generateToken]中的加密逻辑执行反向解密操作, 假如加密流程正常, 则通过这个方法可以得到正确的原文
     *
     * @param clientId 客户端标识
     * @param token 除了客户端标识外, 额外用于区别用户的编码
     * @param base64encoded  经过加密的内容, 这个内容被加密后还执行了一次base64压缩
     * @return 解密后的内容; 由于解密过程中会访问缓存, 所以结果是异步返回的
     */
    @Throws(CacheInvalidException::class)
    fun decodeContent(clientId: String, token: String, base64encoded: String): Future<String>

    /**
     * 生成一段随机字符串, 其中只包含英文字母和数字
     *
     * @param len 生成字符串的长度, 默认8个字符
     */
    fun generateRandomString(len: Int = 8): String

    fun encodePasswordBySalt(password: String, salt: String): String

    fun matchPassword(password: String, encodedPassword: String, salt: String): Boolean

    /**
     * 公钥, 已进行压缩处理, 使用时需要解压
     *
     * @param appId 随机生成的编号, 根据这个编号可以找到用户的私钥
     * @param publicKey 公钥, 用户用此公钥加密
     */
    data class EncodeToken(
        val appId: String,
        val publicKey: String
    )

    companion object {
        operator fun invoke(): TokenService {
            return InternalTokenServiceImpl
        }
    }
}